import { LngLat, type LngLatLike } from 'mapbox-gl';
import type { Mapless } from '..';
import type { IdHubType } from '../core/IdHub';
import IdHub from '../core/IdHub';
import { Manager } from '../core/manager';
import { getOption } from '../core/utils';
import type { HeatmapManagerOptions } from '../index.d';

type HeatmapIdHubType = IdHubType & {
  heatmapLayerId: string;
  heatmapSourceId: string;
};

export default class HeatmapManager extends Manager<HeatmapIdHubType> {
  private points: LngLatLike[] | undefined = undefined;
  private maxPoints: number;

  constructor(mapless: Mapless, options?: HeatmapManagerOptions) {
    super(mapless, options, 'heatmap');
    this.onInitialized();
    // 设置最大点数，默认为1000
    this.maxPoints = getOption<number>('maxPoints', options, 1000);
    this.points = [];
  }

  override createIdHub(_idHub?: IdHubType) {
    const newHub = new IdHub({
      layers: {
        heatmapLayerId: 'dzmap-heatmap-layer',
      },
      sources: {
        heatmapSourceId: 'dzmap-heatmap-source',
      },
    }) as HeatmapIdHubType;
    super.createIdHub(newHub);
  }

  override initLayers() {
    if (!this.mapless) return;
    const sid = this.idHub?.heatmapSourceId;
    this.mapless.addEmptySource(sid);
    // 添加热力图图层
    this.mapless.addLayer({
      id: this.idHub?.heatmapLayerId,
      type: 'heatmap',
      source: sid,
      maxzoom: 15,
      paint: {
        // 热力图颜色强度
        'heatmap-weight': {
          property: 'weight',
          type: 'identity',
        },
        // 颜色渐变
        'heatmap-color': [
          'interpolate',
          ['linear'],
          ['heatmap-density'],
          0,
          'rgba(33,102,172,0)',
          0.2,
          'rgb(103,169,207)',
          0.4,
          'rgb(209,229,240)',
          0.6,
          'rgb(253,219,199)',
          0.8,
          'rgb(239,138,98)',
          1,
          'rgb(178,24,43)',
        ],
        // 热力图半径
        'heatmap-radius': 25,
        // 热力图透明度
        'heatmap-opacity': 0.8,
      },
    });
  }

  private _updateDraw() {
    // 更新数据源
    const features = this.points?.map((point) => ({
      type: 'Feature',
      properties: { weight: 1 },
      geometry: {
        type: 'Point',
        coordinates: LngLat.convert(point).toArray(),
      },
    })) as GeoJSON.Feature[];
    this.mapless?.setData(this.idHub?.heatmapSourceId, {
      type: 'FeatureCollection',
      features,
    });
  }

  drawHeatmap(points: LngLatLike[]) {
    this.points = points;
    this._updateDraw();
  }

  updateHeatmap(points: LngLatLike[], maxPoints?: number) {
    // 更新最大点数限制
    if (maxPoints !== undefined) {
      this.maxPoints = maxPoints;
    }
    // 添加新点并限制总数
    this.points = [...(this.points || []), ...points].slice(-this.maxPoints);
    this._updateDraw();
  }

  removeHeatmap() {
    this.mapless?.setEmptyData(this.idHub?.heatmapSourceId);
    this.points = [];
  }

  override destroy() {
    super.destroy();
    this.points = undefined;
  }
}

export const attachHeatmap = (
  mapless: Mapless | undefined,
  name?: string,
  options?: HeatmapManagerOptions,
) => mapless?.use(HeatmapManager, name, options);
export const getHeatmap = (mapless: Mapless | undefined, name?: string) =>
  mapless?.get(HeatmapManager, name);
export const detachHeatmap = (mapless: Mapless | undefined, name?: string) =>
  mapless?.unuse(HeatmapManager, name);
